/*
 * Copyright 2003-2007 (c) Live Media Pty Ltd. <argot@einet.com.au> 
 *
 * This software is licensed under the Argot Public License 
 * which may be found in the file LICENSE distributed 
 * with this software.
 *
 * More information about this license can be found at
 * http://www.einet.com.au/License
 * 
 * The Developer of this software is Live Media Pty Ltd,
 * PO Box 4591, Melbourne 3001, Australia.  The license is subject 
 * to the law of Victoria, Australia, and subject to exclusive 
 * jurisdiction of the Victorian courts.
 */

package com.colony.transport.socket;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import java.net.ServerSocket;
import java.net.Socket;

import com.argot.network.TypeEndPoint;
import com.argot.network.TypeLink;

import com.colony.transport.Server;
import com.colony.concurrent.ThreadActivator;


public class SocketServer
extends Server
{
	private ServerSocket _socket;
	private boolean _isClosed;
	
	public SocketServer( TypeLink back, ThreadActivator pool, ServerSocket socket )
	{
		super( back, pool );
		_socket = socket;
		_isClosed = false;
	}

	public SocketServer( ThreadActivator pool, ServerSocket socket )
	{
		this( null, pool, socket );
	}
	
	/**
	 * Method connect. This sets up a thread to wait on connections
	 * It must be called after the Node is setup in a Zone.
	 */
	public boolean connect()
	{
     	return getPool().assignThread( new SocketServerWorker() );
	}
	
	public void disconnect() throws IOException
	{
		_isClosed = true;
		_socket.close();
	}

   private class SocketServerWorker
   implements Runnable
   {
   	public void run()
   	{
   		try
   		{
   			connectServer();
   		}
   		catch( IOException ex )
   		{
   			if ( !_isClosed )
   				throw new IllegalStateException(ex);
   		}
   	}
   }

   private void connectServer(  )
   throws IOException
   {

		while ( true )
		{
			Socket clientSocket = _socket.accept();
			InputStream input = clientSocket.getInputStream();
			OutputStream output = clientSocket.getOutputStream();
       	 
			boolean assigned = assignServerThread( new SocketRequest( new BufferedInputStream(input), new BufferedOutputStream(output), clientSocket) );
			if ( !assigned )
				System.err.println( "Error: failed to assign thread" );
      }
   }
   
	protected void processFinish( TypeEndPoint req ) 
	{
		SocketRequest request = (SocketRequest) req;
		Socket socket = request.getSocket();
		try 
		{
			socket.shutdownOutput();
		} 
		catch (IOException e) 
		{
			// do nothing.
		}

		try 
		{
			socket.close();
		} 
		catch (IOException e) 
		{
			// do nothing.
		} 		
	}

}
